package com.tianji.promotion.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.promotion.domain.dto.CouponFormDTO;
import com.tianji.promotion.domain.dto.CouponIssueFormDTO;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.CouponScope;
import com.tianji.promotion.domain.query.CouponQuery;
import com.tianji.promotion.domain.vo.CouponDetailVO;
import com.tianji.promotion.domain.vo.CouponPageVO;
import com.tianji.promotion.domain.vo.CouponScopeVO;
import com.tianji.promotion.enums.CouponStatus;
import com.tianji.promotion.enums.ObtainType;
import com.tianji.promotion.mapper.CouponMapper;
import com.tianji.promotion.service.ICouponScopeService;
import com.tianji.promotion.service.ICouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.service.IExchangeCodeService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import static com.tianji.promotion.enums.CouponStatus.*;
import static com.tianji.promotion.enums.CouponStatus.UN_ISSUE;

/**
 * <p>
 * 优惠券的规则信息 服务实现类
 * </p>
 *
 * @author wjq
 * @since 2023-06-04
 */
@Service
@RequiredArgsConstructor
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {

    private final ICouponScopeService scopeService;
    private final IExchangeCodeService codeService;
    /**
     * 新增优惠券
     * @param dto
     */
    @Override
    @Transactional
    public void saveCoupon(CouponFormDTO dto) {
        // 1.保存优惠券
        // 1.1.转PO
        Coupon coupon = BeanUtils.copyBean(dto, Coupon.class);
        // 1.2.保存
        save(coupon);
        // 没有范围限定
        if (!coupon.getSpecific()){
            return;
        }
        Long couponId = coupon.getId();
        // 2.保存限定范围
        List<Long> scopes = dto.getScopes();
        if (CollUtils.isEmpty(scopes)){
            throw new BadRequestException("限定范围不能为空");
        }
        // 2.1.转换PO
        List<CouponScope> list = scopes.stream()
                .map(bizId -> new CouponScope().setBizId(bizId).setCouponId(couponId))
                .collect(Collectors.toList());
        // 2.2.保存
        scopeService.saveBatch(list);
    }

    /**
     * 分页查询优惠券
     * @param query
     * @return
     */
    @Override
    public PageDTO<CouponPageVO> queryCouponByPage(CouponQuery query) {

        // 1.分页查询
        Page<Coupon> page = lambdaQuery()
                .eq(query.getType() != null, Coupon::getDiscountType, query.getType())
                .eq(query.getStatus() != null, Coupon::getStatus, query.getStatus())
                .like(StringUtils.isNotBlank(query.getName()), Coupon::getName, query.getName())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        // 2.处理VO
        List<Coupon> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }
        List<CouponPageVO> list = BeanUtils.copyList(records, CouponPageVO.class);
        //3.返回
        return PageDTO.of(page,list);
    }

    /**
     * 修改优惠券
     * @param couponDTO
     */
    @Override
    public void updateCoupon(CouponFormDTO couponDTO) {
        // 查询旧数据
        Coupon old = getById(couponDTO.getId());
        if (old == null) {
            throw new BadRequestException("数据不存在");
        }
        // 更新优惠券
        Coupon coupon = BeanUtils.copyBean(couponDTO, Coupon.class);
        // 避免修改状态
        coupon.setStatus(null);
        // 更新
        updateById(coupon);

        // 判断是否要设定新的优惠券范围
        if (couponDTO.getSpecific() == null || (!old.getSpecific() && !couponDTO.getSpecific())) {
            // 4.1.本次修改没有指定范围，直接结束
            return;
        }
        // 本次修改指定了范围，判断范围数据是否存在
        if (couponDTO.getSpecific() && CollUtils.isEmpty(couponDTO.getScopes())) {
            // 没有指定新范围，直接结束
            return;
        }

        // 删除旧限定范围
        Long couponId = coupon.getId();
        scopeService.removeByCouponId(couponId);

        // 添加新范围

        List<CouponScope> list = couponDTO.getScopes().stream()
                .map(bizId -> new CouponScope().setBizId(bizId).setCouponId(couponId))
                .collect(Collectors.toList());

        scopeService.saveBatch(list);
    }

    /**
     * 删除优惠券
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        boolean success = remove(new LambdaQueryWrapper<Coupon>()
                .eq(Coupon::getId, id)
                .eq(Coupon::getStatus, DRAFT)
        );
        if (!success) {
            throw new BadRequestException("优惠券不存在或者优惠券正在使用中");
        }
    }

    /**
     * 根据id查询优惠券（写完）
     * @param id
     * @return
     */
    @Override
    public CouponDetailVO queryCouponById(Long id) {
        // 1.查询优惠券
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new BadRequestException("数据不存在");
        }

        // 2.数据转换
        CouponDetailVO vo = BeanUtils.toBean(coupon, CouponDetailVO.class);

        // 3.查询优惠券关联的使用范围
        Boolean specific = coupon.getSpecific();
        // 3.1.没有限定范围，无需额外查询
        if (!specific) {
            return vo;
        }
        // 3.2.限定使用范围，查询范围
        List<CouponScopeVO> list = scopeService.queryScopeByCouponId(id);
        // 3.3.转换Scope为DTO
        vo.setScopes(list);
        // 4.查看优惠券折扣
        vo.setDiscountValue(coupon.getDiscountValue());
        return vo;

    }

    /**
     * 发放优惠券
     * @param dto
     */
    @Override
    @Transactional
    public void beginIssue(CouponIssueFormDTO dto) {
        // 1.查询优惠券
        Coupon coupon = getById(dto.getId());
        if (coupon == null) {
            throw new BadRequestException("优惠券不存在！");
        }
        // 2.判断优惠券状态，是否是暂停或待发放
        if(coupon.getStatus() != DRAFT && coupon.getStatus() != PAUSE){
            throw new BizIllegalException("优惠券状态错误！");
        }

        // 3.判断是否是立刻发放
        LocalDateTime issueBeginTime = dto.getIssueBeginTime();
        LocalDateTime now = LocalDateTime.now();
        boolean isBegin = issueBeginTime == null || !issueBeginTime.isAfter(now);
        // 4.更新优惠券
        // 4.1.拷贝属性到PO
        Coupon c = BeanUtils.copyBean(dto, Coupon.class);
        // 4.2.更新状态
        if (isBegin) {
            c.setStatus(ISSUING);
            c.setIssueBeginTime(now);
        }else{
            c.setStatus(UN_ISSUE);
        }
        // 4.3.写入数据库
        updateById(c);

        // TODO 兑换码生成
        // 5.判断是否需要生成兑换码，优惠券类型必须是兑换码，优惠券状态必须是待发放
        if(coupon.getObtainWay() == ObtainType.ISSUE && coupon.getStatus() == CouponStatus.DRAFT){
            coupon.setIssueEndTime(c.getIssueEndTime());
            codeService.asyncGenerateCode(coupon);
        }
    }
}
